package cn.com.shadowless.baseview.base.view;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.viewbinding.ViewBinding;

import java.lang.reflect.InvocationTargetException;

import cn.com.shadowless.baseview.event.ViewPublicEvent;
import cn.com.shadowless.baseview.lifecycle.BaseQuickLifecycle;

/**
 * 基础对话框类
 *
 * @param <VB> ViewBinding类型参数
 * @author sHadowLess
 */
public abstract class BaseDialog<VB extends ViewBinding> extends Dialog implements
        ViewPublicEvent.InitViewBinding<VB>, ViewPublicEvent.InitBindingEvent,
        ViewPublicEvent.InitViewClick, BaseQuickLifecycle {

    /**
     * 对话框窗口参数
     */
    private WindowManager.LayoutParams layoutParams;

    /**
     * 对话框窗口对象
     */
    private Window window;

    /**
     * 上下文环境
     */
    private final Context context;

    /**
     * 视图绑定对象
     */
    private VB bind;

    /**
     * 是否已恢复状态
     */
    private boolean isResumed = false;

    /**
     * 是否已添加布局监听器
     */
    private boolean isLayoutListenerAdded = false;

    /**
     * 可见性变化监听器
     */
    private final View.OnLayoutChangeListener visibilityListener =
            (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> updateLifecycleFromVisibility();

    /**
     * 生命周期注册器
     */
    private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);

    /**
     * 对话框设置参数
     */
    private final DialogSetting setting;

    /**
     * 对话框设置类
     */
    public static class DialogSetting {
        /**
         * 对话框参数数组
         */
        private int[] dialogParams;
        /**
         * 对话框位置
         */
        private int dialogPosition;
        /**
         * 是否清除内边距
         */
        private boolean clearPadding;
        /**
         * 是否允许外部点击取消
         */
        private boolean cancelOutside;
        /**
         * 是否可拖拽
         */
        private boolean isDrag;
        /**
         * 是否有阴影
         */
        private boolean hasShadow;
        /**
         * 窗口标志位设置
         */
        private int setFlag;

        /**
         * 获取对话框参数
         *
         * @return 对话框参数数组
         */
        public int[] getDialogParams() {
            return dialogParams;
        }

        /**
         * 设置对话框参数
         *
         * @param dialogParams 对话框参数数组
         */
        public void setDialogParams(int[] dialogParams) {
            this.dialogParams = dialogParams;
        }

        /**
         * 获取对话框位置
         *
         * @return 对话框位置
         */
        public int getDialogPosition() {
            return dialogPosition;
        }

        /**
         * 设置对话框位置
         *
         * @param dialogPosition 对话框位置
         */
        public void setDialogPosition(int dialogPosition) {
            this.dialogPosition = dialogPosition;
        }

        /**
         * 是否清除内边距
         *
         * @return 是否清除内边距
         */
        public boolean isClearPadding() {
            return clearPadding;
        }

        /**
         * 设置是否清除内边距
         *
         * @param clearPadding 是否清除内边距
         */
        public void setClearPadding(boolean clearPadding) {
            this.clearPadding = clearPadding;
        }

        /**
         * 是否允许外部点击取消
         *
         * @return 是否允许外部点击取消
         */
        public boolean isCancelOutside() {
            return cancelOutside;
        }

        /**
         * 设置是否允许外部点击取消
         *
         * @param cancelOutside 是否允许外部点击取消
         */
        public void setCancelOutside(boolean cancelOutside) {
            this.cancelOutside = cancelOutside;
        }

        /**
         * 是否可拖拽
         *
         * @return 是否可拖拽
         */
        public boolean isDrag() {
            return isDrag;
        }

        /**
         * 设置是否可拖拽
         *
         * @param drag 是否可拖拽
         */
        public void setDrag(boolean drag) {
            isDrag = drag;
        }

        /**
         * 是否有阴影
         *
         * @return 是否有阴影
         */
        public boolean isHasShadow() {
            return hasShadow;
        }

        /**
         * 设置是否有阴影
         *
         * @param hasShadow 是否有阴影
         */
        public void setHasShadow(boolean hasShadow) {
            this.hasShadow = hasShadow;
        }

        /**
         * 获取窗口标志位设置
         *
         * @return 窗口标志位设置
         */
        public int getSetFlag() {
            return setFlag;
        }

        /**
         * 设置窗口标志位
         *
         * @param setFlag 窗口标志位
         */
        public void setSetFlag(int setFlag) {
            this.setFlag = setFlag;
        }
    }

    /**
     * 普通对话框构造函数
     *
     * @param context 上下文环境
     */
    public BaseDialog(@NonNull Context context) {
        this(context, 0);
    }

    /**
     * 指定主题对话框构造函数
     *
     * @param context    上下文环境
     * @param themeResId 主题资源ID
     */
    public BaseDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
        this.context = context;
        this.setting = setDialogParam();
        if (getObserveLifecycleOwner() != null) {
            getObserveLifecycleOwner().getLifecycle().addObserver(this);
        }
        handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initObject(savedInstanceState);
        initDialogAttr();
        addVisibilityListener();
        initEvent();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (lifecycleRegistry.getCurrentState() == Lifecycle.State.CREATED) {
            handleLifecycleEvent(Lifecycle.Event.ON_START);
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (lifecycleRegistry.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
            handleLifecycleEvent(Lifecycle.Event.ON_STOP);
            isResumed = false;
        }
    }

    @Override
    public void onDetachedFromWindow() {
        if (isLayoutListenerAdded && window != null) {
            window.getDecorView().removeOnLayoutChangeListener(visibilityListener);
            isLayoutListenerAdded = false;
        }
        super.onDetachedFromWindow();
    }

    @Override
    public void show() {
        super.show();
        if (lifecycleRegistry.getCurrentState() == Lifecycle.State.CREATED) {
            handleLifecycleEvent(Lifecycle.Event.ON_START);
            handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
            isResumed = true;
        }
        initDialog();
        initData();
    }

    @Override
    public void dismiss() {
        if (lifecycleRegistry.getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
            handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
            isResumed = false;
        }
        if (lifecycleRegistry.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
            handleLifecycleEvent(Lifecycle.Event.ON_STOP);
        }
        handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
        super.dismiss();
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }

    @Override
    public LifecycleOwner getObserveLifecycleOwner() {
        if (context instanceof LifecycleOwner) {
            return (LifecycleOwner) context;
        }
        return null;
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            if (getObserveLifecycleOwner() != null) {
                getObserveLifecycleOwner().getLifecycle().removeObserver(this);
            }
            this.dismiss();
        }
    }

    /**
     * 获取绑定的视图对象
     *
     * @return 绑定的视图对象
     */
    @Override
    public VB getBindView() {
        return bind;
    }

    @Override
    public void initEvent() {
        initView();
        initViewListener();
        initDataListener();
    }

    @Override
    public void syncInitView() {

    }

    @Override
    public void asyncInitView() {

    }

    @Override
    public boolean isLazyInitSuccess() {
        return false;
    }

    /**
     * 添加可见性监听器
     */
    private void addVisibilityListener() {
        if (!isLayoutListenerAdded && window != null) {
            window.getDecorView().addOnLayoutChangeListener(visibilityListener);
            isLayoutListenerAdded = true;
        }
    }

    /**
     * 根据可见性更新生命周期状态
     */
    private void updateLifecycleFromVisibility() {
        if (window == null) {
            return;
        }
        boolean isVisible = window.getDecorView().getVisibility() == View.VISIBLE;
        if (isVisible && !isResumed) {
            if (lifecycleRegistry.getCurrentState() == Lifecycle.State.STARTED) {
                lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
                isResumed = true;
            }
        } else if (!isVisible && isResumed) {
            if (lifecycleRegistry.getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
                lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
                isResumed = false;
            }
        }
    }

    /**
     * 处理生命周期事件
     *
     * @param event 生命周期事件
     */
    private void handleLifecycleEvent(Lifecycle.Event event) {
        if (lifecycleRegistry.getCurrentState() != Lifecycle.State.DESTROYED) {
            lifecycleRegistry.handleLifecycleEvent(event);
        }
    }

    /**
     * 初始化对话框属性
     */
    private void initDialogAttr() {
        window = this.getWindow();
        //无标题
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        //子类设置是否外部关闭
        this.setCanceledOnTouchOutside(setting.isCancelOutside());
        //动态创建/初始化顶层容器
        try {
            bind = inflateView(this, getLayoutInflater());
        } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
            throw new RuntimeException("视图无法反射初始化，若动态布局请检查setBindViewClass是否传入或重写inflateView手动实现ViewBinding创建" + Log.getStackTraceString(e));
        }
        //是否清除边框
        if (setting.isClearPadding()) {
            window.getDecorView().setPadding(0, 0, 0, 0);
        }
        //填充顶级容器
        this.setContentView(bind.getRoot());
    }

    /**
     * 初始化对话框位置和参数
     */
    @SuppressLint("WrongConstant")
    private void initDialog() {
        if (!setting.isHasShadow()) {
            window.setDimAmount(0f);
        }
        window.setGravity(setting.getDialogPosition());
        layoutParams = window.getAttributes();
        int[] params = setting.getDialogParams();
        if (params != null && params.length >= 4) {
            layoutParams.x = params[0];
            layoutParams.y = params[1];
            layoutParams.width = params[2];
            layoutParams.height = params[3];
        } else {
            layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
            layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
        }
        int flag = setting.getSetFlag();
        if (flag != 0) {
            layoutParams.flags = flag;
        }
        if (setting.isDrag()) {
            window.getDecorView().setOnTouchListener(new FloatingOnTouchListener());
        }
        window.setAttributes(layoutParams);
    }

    /**
     * 浮动触摸监听器
     */
    private class FloatingOnTouchListener implements View.OnTouchListener {
        /**
         * 触摸点X坐标
         */
        private int x;
        /**
         * 触摸点Y坐标
         */
        private int y;

        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View view, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    x = (int) event.getRawX();
                    y = (int) event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int nowX = (int) event.getRawX();
                    int nowY = (int) event.getRawY();
                    int movedX = nowX - x;
                    int movedY = nowY - y;
                    x = nowX;
                    y = nowY;
                    layoutParams.x = layoutParams.x + movedX;
                    layoutParams.y = layoutParams.y + movedY;
                    window.setAttributes(layoutParams);
                    break;
                default:
                    break;
            }
            return false;
        }
    }

    /**
     * 设置对话框参数
     *
     * @return 对话框设置参数对象
     */
    protected abstract DialogSetting setDialogParam();
}